package event

import (
	"context"
	"errors"
	"fmt"
	"gitee.com/simple-set/simple.io/src/socket"
	"io"
	"log/slog"
	"net"
	"reflect"
)

// StarterServer 服务端启动器接口
type StarterServer interface {
	Listen() error
	Listener() net.Listener
	Close() error
}

// 服务端模式的启动器
type starterServer struct {
	ctx    context.Context
	server socket.Server
	event  *Event
}

func newStarterServer(server socket.Server, event *Event, ctx context.Context) *starterServer {
	return &starterServer{server: server, event: event, ctx: ctx}
}

func (s *starterServer) Listen() error {
	for {
		select {
		case <-s.ctx.Done():
			slog.Debug(reflect.ValueOf(s.server).Elem().Type().String() + " Context revocation, stop listening")
			_ = s.Close()
			return nil
		default:
			sock, err := s.server.Listen()
			if err != nil {
				// 监听新会话异常
				_ = s.Close()
				return err
			} else {
				// 创建并处理新会话
				go s.handler(NewSessionContext(sock, s.ctx))
			}
		}
	}
}

func (s *starterServer) Close() error {
	if s.server == nil {
		return errors.New("server is nil")
	}
	return s.server.Close()
}

func (s *starterServer) Listener() net.Listener {
	return s.server.Listener()
}

func (s *starterServer) handler(session *Session) {
	//remoteAddr := session.Socket.RemoteAddr().String()
	if s.event == nil {
		session.Logger.Error("event is nil")
		_ = session.Close()
		return
	}

	session.setState(Accept)
	if err := s.execAccept(session); err != nil {
		session.Logger.Error("execAccept exception", "err", err.Error())
		_ = session.Close()
		return
	}

	session.setState(Active)
	if err := s.execActive(session); err != nil {
		session.Logger.Error("execActive exception", "err", err.Error())
		_ = session.Close()
		return
	}

	session.setState(Disconnect)
	if err := s.execDisconnect(session); err != nil {
		session.Logger.Error("execDisconnect exception", "err", err.Error())
		_ = session.Close()
		return
	}

	if session.Socket.IsTcp() {
		if err := session.Close(); err != nil {
			session.Logger.Warn("session.close error,", "err", err.Error())
		}
	}
	session.Logger.Debug("disconnect")
	return
}

func (s *starterServer) execAccept(session *Session) error {
	if session.state != Accept {
		return fmt.Errorf("execAccept reject, Session state mismatch, %v", session.state)
	}
	_, err := s.event.execute(session, nil)
	return err
}

func (s *starterServer) execActive(session *Session) error {
	if session.state != Active {
		return fmt.Errorf("execActive reject, Session state mismatch, %v", session.state)
	}

	for {
		if err := session.Socket.Wait(); err == io.EOF {
			return nil
		} else if err != nil {
			return err
		}

		if _, err := s.event.execute(session, nil); err == io.EOF {
			return nil
		} else if err != nil {
			return err
		}
	}
}

func (s *starterServer) execDisconnect(session *Session) error {
	if session.state != Disconnect {
		return fmt.Errorf("execDisconnect reject, Session state mismatch, %v", session.state)
	}
	_, err := s.event.execute(session, nil)
	return err
}
